/* Linear3D.m */

#import "Linear3D.h"
#import <math.h>

@implementation Linear3D

+new
{
	int ctr1,ctr2;
	self=[super new];
	for(ctr1=0;ctr1<4;++ctr1) {
		for(ctr2=0;ctr2<4;++ctr2) {	
			coeff[ctr1][ctr2]=0.0;
		}
	}
	coeff[0][0]=1.0;
	coeff[1][1]=1.0;
	coeff[2][2]=1.0;	
	return self;
}

- operateOn:(vector3D *)theVect
{
	vector3D temp;
	temp.x=theVect->x*coeff[0][0]+theVect->y*coeff[1][0]+
		theVect->z*coeff[2][0]+coeff[3][0];
	temp.y=theVect->x*coeff[0][1]+theVect->y*coeff[1][1]+
		theVect->z*coeff[2][1]+coeff[3][1];
	temp.z=theVect->x*coeff[0][2]+theVect->y*coeff[1][2]+
		theVect->z*coeff[2][2]+coeff[3][2];
	*theVect=temp;
	return self;
}
	
- operateOn:(vector3D *)theVects howMany:(int)count;
{
	vector3D temp;
	int ctr;
	for(ctr=0;ctr<count;++ctr){
		temp.x=theVects[ctr].x*coeff[0][0]+theVects[ctr].y*coeff[1][0]+
			theVects[ctr].z*coeff[2][0]+coeff[3][0];
		temp.y=theVects[ctr].x*coeff[0][1]+theVects[ctr].y*coeff[1][1]+
			theVects[ctr].z*coeff[2][1]+coeff[3][1];
		temp.z=theVects[ctr].x*coeff[0][2]+theVects[ctr].y*coeff[1][2]+
			theVects[ctr].z*coeff[2][2]+coeff[3][2];
		theVects[ctr]=temp;
	}
	return self;
}

- concatBefore:aLinear
{
	int ctrRow,ctrColumn,ctr;
	float temp[4][3];
	if([aLinear isKindOf:[Linear3D class]]) {
		for(ctrRow=0;ctrRow<3;++ctrRow) {
			for(ctrColumn=0;ctrColumn<3;++ctrColumn) {
				temp[ctrRow][ctrColumn]=0.0;
				for(ctr=0;ctr<3;++ctr)
					temp[ctrRow][ctrColumn] += 
						coeff[ctrRow][ctr]*
						[aLinear coefficient:ctr column:ctrColumn];
			}
		}
		for(ctr=0;ctr<3;++ctr)
			temp[3][ctr]=coeff[3][0]*[aLinear coefficient:0 column:ctr]+
				coeff[3][1]*[aLinear coefficient:1 column:ctr]+
				coeff[3][2]*[aLinear coefficient:2 column:ctr]+
				[aLinear coefficient:3 column:ctr];
				
		for(ctrRow=0;ctrRow<4;++ctrRow)
			for(ctrColumn=0;ctrColumn<3;++ctrColumn)
				coeff[ctrRow][ctrColumn]=temp[ctrRow][ctrColumn];
		return self;
	}
	return nil;
}

- concatAfter:aLinear
{
	int ctrRow,ctrColumn,ctr;
	float temp[4][3];
	if([aLinear isKindOf:[Linear3D class]]) {
		for(ctrRow=0;ctrRow<3;++ctrRow) {
			for(ctrColumn=0;ctrColumn<3;++ctrColumn) {
				temp[ctrRow][ctrColumn]=0.0;
				for(ctr=0;ctr<3;++ctr)
					temp[ctrRow][ctrColumn] += 
						coeff[ctr][ctrColumn]*
						[aLinear coefficient:ctrRow column:ctr];
			}
		}
		for(ctr=0;ctr<3;++ctr)
			temp[3][ctr]=coeff[0][ctr]*[aLinear coefficient:3 column:0]+
				coeff[1][ctr]*[aLinear coefficient:3 column:1]+
				coeff[2][ctr]*[aLinear coefficient:3 column:2]+
				coeff[3][ctr];
				
		for(ctrRow=0;ctrRow<4;++ctrRow)
			for(ctrColumn=0;ctrColumn<3;++ctrColumn)
				coeff[ctrRow][ctrColumn]=temp[ctrRow][ctrColumn];
		return self;
	}
	return nil;
}

- rotation:(int)axis:(float)angle
{
	int ctrRow,ctrColumn;
	
	angle *= 3.14159/180.0;
	
	for(ctrRow=0;ctrRow<4;++ctrRow)
		for(ctrColumn=0;ctrColumn<3;++ctrColumn)
			coeff[ctrRow][ctrColumn]=0.0;

	coeff[0][0]=1.0;
	coeff[1][1]=1.0;
	coeff[2][2]=1.0;

	switch(axis) {
		case L3D_X_AXIS:
			coeff[1][1]=cos(angle);
			coeff[2][2]=cos(angle);
			coeff[1][2]=sin(angle);
			coeff[2][1]=-sin(angle);
			break;
		case L3D_Y_AXIS:
			coeff[0][0]=cos(angle);
			coeff[2][2]=cos(angle);
			coeff[0][2]=-sin(angle);
			coeff[2][0]=sin(angle);
			break;
		case L3D_Z_AXIS:
			coeff[0][0]=cos(angle);
			coeff[1][1]=cos(angle);
			coeff[0][1]=sin(angle);
			coeff[1][0]=-sin(angle);
			break;
	}
	return self;
}		

- scaling:(float)x:(float)y:(float)z
{
	int ctrRow,ctrColumn;
	
	for(ctrRow=0;ctrRow<4;++ctrRow)
		for(ctrColumn=0;ctrColumn<3;++ctrColumn)
			coeff[ctrRow][ctrColumn]=0.0;

	coeff[0][0]=x;
	coeff[1][1]=y;
	coeff[2][2]=z;
			
	return self;
}

- translation:(float)x:(float)y:(float)z
{
	int ctrRow,ctrColumn;
	
	for(ctrRow=0;ctrRow<4;++ctrRow)
		for(ctrColumn=0;ctrColumn<3;++ctrColumn)
			coeff[ctrRow][ctrColumn]=0.0;

	coeff[0][0]=1.0;
	coeff[1][1]=1.0;
	coeff[2][2]=1.0;

	coeff[3][0]=x;
	coeff[3][1]=y;
	coeff[3][2]=z;
			
	return self;
}

- (float)coefficient:(int)row column:(int)column
{
	if(row > 3 || column > 2 || row < 0 || column < 0) return 0.0;
	return coeff[row][column];
}


@end
